#pragma once
#include "../src/headfile.h"
/***********************************全局变量的声明***********************************/
/**
 * @param num_Scan    接收多少个点
 * @param epsilon  最小距离
 *  @param minPoints  簇附近最小有多少点
 * @param maxDistance  距离上限
 */
struct Lidar
{
    int ori_num_Scan = 3580;
    int num_Scan = 3580;
    double epsilon = 25;
    int minPoints = 4;
    int maxDistance = 500; // 5米
    int Features_Nums = 25;
};
extern Lidar Lidar_init;

struct Feature_Parameters
{
    double num_Points;               // 1.激光点数量
    double average_angleDiff;        // 2.平均角度差
    double centerX, centerY, radius; // 3.拟合圆的参数来代替圆弧半径
    double arc_length;               // 4.弧长
    double average_widthDiff;        // 5.平均线段宽度
    double average_curvature;        // 6.平均曲率
    double sum_Point2Center;         // 7.点到圆心的和
    double xPoint2Center_mean;       // 8.点到圆心的X坐标差的均值
    double yPoint2Center_mean;       //     点到圆心的Y坐标差的均值
    double xPoint2SortX;             // 9.点到中位置的X坐标标准差
    double yPoint2SortY;             //     点到中位置的Y坐标标准差
    double xPoint2averageX;          // 10.点到平均的X坐标方差
    double yPoint2averageY;          //     点到平均的Y坐标方差
    double xKurtosis;                // 11.X方向峰度
    double yKurtosis;                //     Y方向峰度
    double xSkewness;                // 12.X方向峰度
    double ySkewness;                //     Y方向峰度
    double cen_x_zero_sum;           // x坐标大于圆心小于0
    double zero_x_cen_sum;           // x坐标大于0小于圆心
    double cen_y_zero_sum;           // y坐标大于圆心小于0
    double zero_y_cen_sum;           // y坐标大于0小于圆心
    double x_cen_sum;                // x坐标小于圆心
    double cen_x_sum;                // x坐标大于圆心
    double y_cen_sum;                // y坐标小于圆心
    double cen_y_sum;                // y坐标大于圆心
    int is_Foot;
};

/**
 * @param x    角度
 * @param y  距离
 */
struct Lidar_Point
{
    float x, y; // 假设数据点具有x和y坐标
    int32_t category;
};
extern std::vector<Lidar_Point> Lidar_data;
extern std::vector<Lidar_Point> Lidar_class_data;

/***********************************非模板函数的声明***********************************/

std::vector<int> findNeighbors(const std::vector<Lidar_Point> &data, int pointIdx, double epsilon, int range, std::vector<int> &isvalid);

/***********************************模板函数的声明***********************************/
// 执行DBSCAN聚类
template <typename T>
void DBSCAN(const std::vector<Lidar_Point> &data, double epsilon, int minPoints, std::vector<int> &cluster, std::vector<T> &arr, std::vector<int> &isvalid)
{
    int clusterId = 0;
    double min_Points = 0;
    double temp = 0;
    const int Find_Nums = Lidar_init.num_Scan / 3.58;
    // 聚类
    for (int i = 0; i < data.size(); ++i)
    {
        if ((cluster[i] != -1 && arr[i] != -1))
        {
            continue; // 已分配到簇中，跳过
        }
        std::vector<int> neighbors = findNeighbors(data, i, epsilon, Find_Nums, isvalid);
        if (neighbors.size() < minPoints || isvalid[i] == 1)
        {
            cluster[i] = 0; // 噪声点
            arr[i] = 0;
        }
        else
        {
            clusterId++;
            cluster[i] = clusterId;
            arr[i] = clusterId;
            for (int j = 0; j < neighbors.size(); ++j)
            {
                int neighborIdx = neighbors[j];

                if (cluster[neighborIdx] == 0)
                {
                    cluster[neighborIdx] = 0;
                    arr[neighborIdx] = 0;
                    continue;
                }

                if (cluster[neighborIdx] != -1)
                {
                    continue; // 已分配到其他簇中的点
                }

                cluster[neighborIdx] = clusterId;
                arr[neighborIdx] = clusterId;
                std::vector<int> neighborNeighbors = findNeighbors(data, neighborIdx, epsilon, Find_Nums, isvalid);
                if (neighborNeighbors.size() >= minPoints)
                {
                    neighbors.insert(neighbors.end(), neighborNeighbors.begin(), neighborNeighbors.end());
                    min_Points += neighborNeighbors.size();
                }
            }
            // temp += min_Points;
        }
    }
    std::cout << (clusterId) << std::endl;
    std::cout << round(min_Points / 2 / Lidar_init.num_Scan) << std::endl;
    Lidar_init.minPoints = round(min_Points / 2 / Lidar_init.num_Scan);
}
